package cn.zyl.demo.common.tools;

import cn.zyl.demo.common.enums.CharsetEnum;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

/**
 * IpScanTool类说明:
 *
 * @author wsz
 * @version v1.0
 * @date 2020-07-24
 */
public class IpScanTool {
    private static final int MAX_IP_SEGMENT = 255;
    private static final int MIN_IP_SEGMENT = 0;
    private static final int TIME_OUT = 3000;
    public static void main(String[] args) {
        //[10.10.0.113, 192.168.56.1, 10.26.128.21, 127.0.0.1]
        //System.out.println(getIpAddress());
        //scannerNetwork("127.0.0.1");
        //pingCmd("111.62.218.58");
        //todo IP地址扫描工具类
    }
    /**
     * 获取本机的IP地址（包括ipv4和ipv6） <br>
     * 包含回环地址127.0.0.1和0:0:0:0:0:0:0:1
     */
    private static Set<String> getIpAddress(){
        Set<String> set = new HashSet<>();
        try {
            //返回此机器上的所有接口。 该Enumeration包含至少一种元素，可能代表一个环回接口仅支持在本机上的实体之间的通信。
            // 注：可以使用getNetworkInterfaces（）+ getInetAddresses（）来获取所有IP地址此节点
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip;
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = allNetInterfaces.nextElement();
                // 排除虚拟接口和没有启动运行的接口
                if (netInterface.isVirtual() || !netInterface.isUp()) { continue; }
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ip = addresses.nextElement();
                    if (ip != null && (ip instanceof Inet4Address)) {
                        set.add(ip.getHostAddress());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return set;
    }
    /**
     * 根据本机ip扫描局域网设备
     * @param set
     */
    private static void scannerNetwork(Set<String> set) {
        try {
            set.forEach(IpScanTool::scannerNetwork);
        } catch (Exception uhe) {
            System.err.println("Unable to find: " + uhe.getLocalizedMessage());
        }
    }
    /**
     * 根据本机ip扫描局域网设备
     * @param address IP地址
     */
    private static void scannerNetwork(String address) {
        // 设置IP地址网段 127.0.0.
        String ips = getNetworkSegment(address),ip;
        System.out.println("开始扫描 " + ips + "网段...");
        InetAddress addip;
        System.out.println("序号\t\tIP地址\t\t\t进度\t\t设备名称\t\t是否可用");
        // 遍历IP地址
        for (int i = MIN_IP_SEGMENT+1; i < MAX_IP_SEGMENT; i++) {
            ip = ips + i;
            System.out.print(i+"\t\t" + ip + "\t\t");
            try {
                addip = InetAddress.getByName(ip);
                System.out.print("*");
                if( null == addip){continue;}
                // 获取登录过的设备
                //if (!ip.equals(addip.getHostName())) { }
                // 检查设备是否在线，其中1000ms指定的是超时时间
                System.out.print("*\t\t"+addip.getHostName() + "\t\t");
                // 当返回值是true时，说明host是可用的，false则不可。
                boolean status = addip.isReachable(TIME_OUT);
                System.out.print((status ? "可用" : "不可用"));
            } catch (UnknownHostException e) {
                System.out.println("找不到主机: " + ip);
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(".");
        }
    }
    public static void pingCmdWin(String ipAddress) {
        try {
            Process pro = Runtime.getRuntime().exec("ping " + ipAddress);
            BufferedReader buf = new BufferedReader(new InputStreamReader(pro.getInputStream(), CharsetEnum.GBK.getType()));
            String line;
            while ((line = buf.readLine()) != null) {
                System.out.println(line);
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }
    /**
     * 根据ip获取网段
     * @param ip IP地址 127.0.0.1
     * @return 网段 127.0.0.
     */
    private static String getNetworkSegment(String ip) {
        return ip.substring(0, ip.lastIndexOf(".")+1);
    }
    public static boolean ping(String ipAddress) throws Exception {
        //超时应该在3钞以上,当返回值是true时，说明host是可用的，false则不可。
        return InetAddress.getByName(ipAddress).isReachable(TIME_OUT);
    }
}
//ip地址的构成 https://blog.csdn.net/weixin_45177186/article/details/91415410
//Java获取本机ip地址,并扫描本机所在局域网的电脑设备 https://www.cnblogs.com/mxh-java/p/13187115.html